#ifndef SOCK5_BASIC_HPP
#define SOCK5_BASIC_HPP

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <dirent.h>
#include <functional>
#include <memory>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define THROW_EXCEPTION(err)                                                      \
    {                                                                             \
        std::ostringstream oss;                                                   \
        oss << err << " -" << strrchr(__FILE__, '/') + 1 << " line:" << __LINE__; \
        std::throw_with_nested(BaseException(oss.str()));                         \
    }

namespace oraysock5 {

/**
 * @brief 异常
*/
class BaseException : public std::exception {
public:
    explicit BaseException(const std::string& msg)
        : msg_(msg)
    {
    }

    BaseException(const BaseException&) = default;
    BaseException& operator=(const BaseException&) = default;

    BaseException(BaseException&&) = default;
    BaseException& operator=(BaseException&&) = default;

    virtual ~BaseException() override = default;

    //异常信息
    virtual const char* what() const noexcept override
    {
        return msg_.data();
    }

private:
    std::string msg_;
};

/**
* @brief 获取当前进程运行目录和程序名称
* @param processdir 当前进程运行目录
* @param processname 程序名称
* @param len 指向存储当前进程运行目录地址的大小
* @return 当前进程运行目录长度
*/
int executable_path(char* processdir, char* processname, size_t len);

/**
* @brief 格式化字符串
* @tparam ...Args 格式参数类型 
* @param format 格式符串
* @param ...args 格式参数
* @return 新的字符串
*/
template <typename... Args>
std::string str_format(const std::string& format, Args... args)
{
    auto size_buf = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...) + 1;
    std::unique_ptr<char[]> buf(new char[size_buf]);
    std::snprintf(buf.get(), size_buf, format.c_str(), std::forward<Args>(args)...);
    return std::string(buf.get(), buf.get() + size_buf - 1);
}

// @return 0 创建成功，或创建前已经存在    -1 失败
int mkdir_recursive(const std::string& pathname);

/**
         * @brief 移除字符串两端的空白字符串
         此函数会修改原始字符串,不会复制
         * @param xstr 待移除字符串
         * @param cb 空白字符串
         * @return 移除字后的符串
        */
std::string& trim(std::string& xstr, std::function<int(int)> cb = ::isspace);

/*
* 输出异常信息
*/
void print_exception(const std::exception& e, int level = 0);

/**
* @brief 写进程id到文件
* @param pidfile 记录进程id的文件名,默认工作目录下,程序名.pid 
*/
void writepid(const char* pidfile);

namespace {

    template <typename T>
    inline void hash_combine(size_t& seed, const T& val)
    {
        seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }

    template <typename T>
    inline void hash_val(size_t& seed, const T& val)
    {
        hash_combine(seed, val);
    }

    template <typename T, typename... Types>
    inline void hash_val(size_t& seed, const T& val, const Types&... args)
    {
        hash_combine(seed, val);
        hash_val(seed, args...);
    }

}

/*
* 利用变参模板和std::hash实现的万能哈希
*   可通过多种类型的多个变量组合生成哈希值，使得哈希结果更均匀
*/
template <typename... Types>
inline size_t hash_val(const Types&... args)
{
    size_t seed = 0;
    hash_val(seed, args...);
    return seed;
}

/**
* @brief 守护进程运行
* @return 进程id
*/
int daemon();

/**
         * @brief 连接断开原因
        */
enum class CloseType {
    /**
         * @brief 客户端主动断开
            */
    CLIENT_CLOSE,
    /**
         * @brief 服务区主动断开
        */
    SERVER_CLOSE,
    /**
             * @brief 连接服务器失败
            */
    CONNECT_FAIL,
    /**
             * @brief 没有心跳超时
            */
    TIMEOUT_CLOSE,
};

/**
     * @brief 管理io缓冲数据处理结果
    */
enum class InputResult {
    SUCCESS = 0,
    /**
         * @brief 主动断开
        */
    INITIATIVE_CLOSE,
    /**
         * @brief 被动断开
        */
    PASSIVE_CLOSE,
    /**
         * @brief 数据包不完整
        */
    DATA_INCOMPLETE,
};

/**
 * @brief 禁止拷贝
*/
class Nocopy {
public:
    Nocopy(const Nocopy&) = delete;
    Nocopy(Nocopy&) = delete;
    Nocopy(Nocopy&&) = delete;
    Nocopy& operator=(const Nocopy&) = delete;
    Nocopy& operator=(Nocopy&) = delete;
    Nocopy& operator=(Nocopy&&) = delete;
    virtual ~Nocopy() = default;

protected:
    Nocopy() = default;
};
}

#endif
